Skip to content

Conversation

@kiendang
Copy link
Contributor

@kiendang kiendang commented Mar 6, 2025

Use Apache Commons Compress to support symlinks and permissions.

This supports os.zip (for new zips, not modification), os.zip.stream and os.unzip.

Supporting symlinks and permissions for os.unzip.stream is impossible since the information is stored in the central directory at the end of the zip file, not together with each zip entry.

ZipFile doesn't support modifying entries in place. Thus os.zip modification would still require jdk.zipfs, which doesn't support symlinks, and only supports permissions since JDK 14.

Apache Commons Compress is quite heavy a dependency since it also includes support for other compressing formats, and also depends on Apache Commons IO. A more light weight alternative would be to vendor org.apache.tools.zip from Apache Ant (which is basically the same thing as Apache Commons Compress). See my other branch that goes with this approach.

What's missing?

  • move to src-jvm
  • make Apache Commons Compress provided dep?
  • add tests
  • make sure this doesn't break anything on Windows

@sake92
Copy link
Collaborator

sake92 commented Mar 6, 2025

os-lib has(had) a ScalaNative build https://github.com/com-lihaoyi/os-lib/blob/main/build.mill#L197-L204
and in the future it might have a ScalaJS (nodejs) build too.
So it is preferrable to add apache-commons-compress only to the JVM build.
This means we'd have to introduce interface(s) for ZIP/UNZIP actions, and implement it for each platform.

Maybe something like:

trait ZipActions {
  def zip(
      dest: os.Path,
      sources: Seq[ZipSource] = List(),
      excludePatterns: Seq[Regex] = List(),
      includePatterns: Seq[Regex] = List(),
      preserveMtimes: Boolean = false,
      deletePatterns: Seq[Regex] = List(),
      compressionLevel: Int = java.util.zip.Deflater.DEFAULT_COMPRESSION
  ): os.Path

  def unzip..
}

and then implement it for JVM as JvmZipActions extends ZipActions via commons-compress.
For native we could drop to shelling out or something, whatever we find working in the future...


Then we can have for JVM:

object PlatformActions {
  val zipActions = new JvmZipActions()
}

and native

object PlatformActions {
  val zipActions = new NativeZipActions()
}

From ZipOps.scala we could call PlatformActions.zipActions.zip(...)

@kiendang kiendang closed this Mar 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants